package ch.sv7.tool.dbmanager.db.xml;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import ch.sv7.tool.dbmanager.DbManagerException;
import ch.sv7.tool.dbmanager.db.ColumnType;
import ch.sv7.tool.dbmanager.db.ColumnTypeManager;
import ch.sv7.tool.dbmanager.db.Field;
import ch.sv7.tool.dbmanager.db.FilePatternManager;
import ch.sv7.tool.dbmanager.db.Row;
import ch.sv7.tool.dbmanager.db.SafeString;
import ch.sv7.tool.dbmanager.db.Table;
import ch.sv7.tool.dbmanager.db.TableSchema;
import ch.sv7.tool.dbmanager.db.TableWriter;
import ch.sv7.tool.xml.XMLDocumentWriter;

public class StringXmlTableWriter implements TableWriter {

	private static final String TAB = "    ";
	
	private String encoding = "UTF-8";
	
	private String directory;

	private String schemaName;

	private String filePattern;

	private int nbRow;

	private String filename;

	private PrintStream writer;

	private boolean zippedFile;

	public StringXmlTableWriter(String directory, String schemaName, String filePattern, boolean zippedFile, String encoding) {
		nbRow = 0;
		filename = null;
		writer = null;
		this.directory = directory;
		this.schemaName = schemaName;
		this.filePattern = filePattern;
		this.zippedFile = zippedFile;
		this.encoding = encoding;
	}

	public void writeHeader(TableSchema schema) throws DbManagerException {
		nbRow = 0;
		filename = directory + System.getProperty("file.separator")
				+ FilePatternManager.getFilename(schema.getName(), schemaName, filePattern)
				+ (zippedFile ? ".zip" : ".xml");
		try {
			if (zippedFile) {
				String entryName = FilePatternManager.getFilename(schema.getName(), schemaName, filePattern) + ".xml";
				ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(filename));
				zos.putNextEntry(new ZipEntry(entryName));
				writer = new PrintStream(zos, false, encoding);
			} else {
				writer = new PrintStream(new FileOutputStream(filename), false, encoding);
			}
		} catch (FileNotFoundException e) {
			throw new DbManagerException("Unable to create file : " + filename, e);
		} catch (IOException e) {
			throw new DbManagerException("Unable to create zipped file : " + filename, e);
		}
		writer.println("<?xml version='1.0' encoding='" + encoding + "'?>");
		writer.println("<table>");
	}

	public void writeFooter(TableSchema tableschema) throws DbManagerException {
		writer.println("</table>");
		writer.flush();
		writer.close();
		System.out.println("Number of rows writed to file : " + nbRow);
	}

	public void writeRow(Row row, TableSchema schema) throws DbManagerException {
		writeRow(row, writer, schema);
		nbRow++;
	}

	public void writeTable(Table table, TableSchema schema) throws DbManagerException {
		writeHeader(schema);
		for (int i = 0; i < table.size(); i++)
			writeRow(table.getRowAt(i), schema);

		writeFooter(schema);
	}

	/*
	 * commented because was never used locally
	 * 
	 * private String filterFilename(String filename) { String charset =
	 * "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_";
	 * StringBuffer result = new StringBuffer(filename); for (int i = 0; i <
	 * result.length(); i++) if (charset.indexOf(result.charAt(i)) == -1)
	 * result.setCharAt(i, '_');
	 * 
	 * return result.toString(); }
	 */

	private void writeRow(Row row, PrintStream writer, TableSchema schema) {
		writer.println(TAB + "<row>");
		for (int i = 0; i < schema.getColumnSchemas().length; i++) {
			Field field = row.getField(schema.getColumnSchemas()[i].getName());
			writeField(field, writer, schema.getColumnSchemas()[i].getType());
		}
		writer.println(TAB + "</row>");
	}

	private void writeField(Field field, PrintStream writer, ColumnType dataType) {
		Object value = field.getValue();
		if (value == null) {
			writer.println(TAB + TAB + "<field name='" + field.getName() + "'><null/></field>");
		} else {
			SafeString strValue = ColumnTypeManager.writeToString(dataType, value);
			if (SafeString.FORMAT_PLAIN.equals(strValue.getFormat())){
				/*
				 * Plain case
				 */
				writer.print(TAB + TAB + "<field name='" + field.getName() + "' format='" + strValue.getFormat() +"'>");
				writer.print("<![CDATA[" + XMLDocumentWriter.fixupEncoding(strValue.getSafeString()) + "]]" + ">");
				
			} else if (SafeString.FORMAT_BASE64.equals(strValue.getFormat())){
				/*
				 *  Base64 case
				 */
				writer.print(TAB + TAB + "<field name='" + field.getName() + "' format='" + strValue.getFormat() +"'>");
				writer.print(strValue.getSafeString());
			} else {
				/*
				 * Default case
				 */
				writer.print(TAB + TAB + "<field name='" + field.getName() + "'>");
				if (ColumnTypeManager.isStoredAsCDATA(dataType)) {
					writer.print("<![CDATA[" + XMLDocumentWriter.fixupEncoding(strValue.getSafeString()) + "]]" + ">");
				} else {
					if (strValue.getSafeString() != null)
						writer.print(XMLDocumentWriter.fixupHtml(strValue.getSafeString()));
				}	
			}			
			writer.println("</field>");
		}
	}
}
